package com.game.core.session;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.game.core.net.common.RemoteNode;
import com.game.core.service.PublicService;

public class SessionService extends PublicService
{
	private static final long serialVersionUID = 2335578523733968238L;

	private static Logger logger = LoggerFactory.getLogger(SessionService.class);

	private AtomicInteger sessionIDSeed = new AtomicInteger();
	
	private Map<Integer, Session> sessionsBySessionID = new ConcurrentHashMap<Integer, Session>(1000);
	private Map<Long, Session> onlineSessions = new ConcurrentHashMap<Long, Session>();

	// <accountId, session>
	private Map<Long, Session> offlineSessions = new ConcurrentHashMap<Long, Session>();

	public Session getOnlineSession(long playerID)
	{
		return onlineSessions.get(playerID);			
	}
	public Session getOfflineSession(long accountId)
	{
		return offlineSessions.get(accountId);
	}
	public Session getSessionsBySessionID(int sessionID)
    {
	    return sessionsBySessionID.get(sessionID);
    }
	public RemoteNode getRemoteNodeBySessionID(int sessionID)
	{
		Session session = sessionsBySessionID.get(sessionID);
		if (session == null)
			return null;
		return session.getRemoteNode();
	}
	public Session getOfflineSessionByRoleId(long roleId)
	{
		for(Map.Entry<Long, Session> entry : offlineSessions.entrySet())
		{
			if(entry.getValue().getRemoteNode().getRoleId() == roleId)
				return entry.getValue();
		}
		return null;
	}
	
	public Session addSession(RemoteNode remoteNode)
	{
		Session session = null;
		if(remoteNode.getAccountId() != 0)
		{
			if(offlineSessions.containsKey(remoteNode.getAccountId()))
				session = offlineSessions.get(remoteNode.getAccountId());
		}
		else
			session = new Session();
		session.setSessionID(sessionIDSeed.incrementAndGet());
		session.setRemoteNode(remoteNode);
		session.setUpSequenceId(0);
		session.setDownSequenceId(0);

		remoteNode.setSession(session);
		remoteNode.setSessionId(session.getSessionID());
		sessionsBySessionID.put(session.getSessionID(), session);
		return session;
	}

	public Session RemoveSession(RemoteNode remoteNode)
	{
		if(!sessionsBySessionID.containsKey(remoteNode.getSessionId()))
			return null;

		Session session = sessionsBySessionID.get(remoteNode.getSessionId());
		if(!onlineSessions.containsKey(remoteNode.getRoleId()))
			if(remoteNode.getRoleId() != 0)
				logger.error("removeSession: can't find session in online session. role id is " + remoteNode.getRoleId());

		onlineSessions.remove(remoteNode.getRoleId());
		sessionsBySessionID.remove(session.getSessionID());
		if(remoteNode.getAccountId() != 0)
			offlineSessions.put(remoteNode.getAccountId(), session);

		return session;
	}
	
	public void clearSession()
	{
		sessionsBySessionID.clear();
		onlineSessions.clear();
		offlineSessions.clear();
	}
	
	public void bindSession(int sessionID, long accountId, long playerID)
	{
		Session session = onlineSessions.get(playerID);
		if(session == null)
			session = sessionsBySessionID.get(sessionID);

		// 这里想加一层保护，但是抛异常是否合适，再看看
		if(session == null)
			throw new RuntimeException("set Player ID fault. player id is " + playerID);

		if(offlineSessions.containsKey(accountId))
		{
			correctSession(accountId, session);
			offlineSessions.remove(accountId);
		}
		
		if(onlineSessions.containsKey(playerID))
			logger.error("setPlayerID: onlineSessions contains playerId, player id is " + playerID);

		onlineSessions.put(playerID, session);
	}	
	
	/**
	 * Session 校正
	 * @param accountId
	 * @param retSession
	 */
	void correctSession(long accountId, Session retSession)
	{
		if(!offlineSessions.containsKey(accountId))
			return;
		
		Session session = offlineSessions.get(accountId);
//		retSession.setClientDownSequenceId(session.getClientDownSequenceId());
//		retSession.setClientUpSequenceId(session.getClientUpSequenceId());
		retSession.setDownSequenceId(session.getDownSequenceId());
		retSession.setUpSequenceId(session.getUpSequenceId());
	}

	/**
	 * 获取在线玩家列表RoleId
	 * @return
	 */
	public List<Long> getOnlineRoleId()
	{
		List<Long> roleIds = new ArrayList<Long>();
		for(Map.Entry<Long, Session> entry : onlineSessions.entrySet())
			roleIds.add(entry.getKey());
		return roleIds;
	}
	
	public List<Long> getOfflineCacheRoleId()
	{
		List<Long> roleIds = new ArrayList<Long>();
		for(Map.Entry<Long, Session> entry : offlineSessions.entrySet())
		{
			long roleId = entry.getValue().getRemoteNode().getRoleId();
			if(roleId != 0)
				roleIds.add(roleId);
		}
		return roleIds;
	}
	
	public Set<Long> getOfflineCacheAccountId()
	{
		return offlineSessions.keySet();
	}
	
	/**
	 * 获取在线玩家数量
	 * @return
	 */
	public int getOnlineRoleCount()
	{
		return onlineSessions.size();
	}
	
	/**
	 * 判断某个玩家是否在线
	 * @param roleId
	 * @return
	 */
	public boolean isOnlineRoleId(long roleId)
	{
		return onlineSessions.containsKey(roleId);
	}
}
